﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Runtime.Remoting.Messaging;
using System.Collections;
using TypedROBIN.Common;

namespace TypedROBIN.Imaging
{
    public class IECaptr : MarshalByRefObject, IIECaptr
    {
        internal static volatile Hashtable CurrentCallers = new Hashtable(1000);
        internal static volatile bool ServiceStopping = false;

        public event CompleteEventHandler OnIECaptComplete;
        public event ErrorEventHandler OnIECaptError;
        public event StatusEventHandler OnIECaptStatus;

        private long StartTicks = 0;
        private long ExecutionTime = 0;
        private Arguments Args = new Arguments(null, null);
        private string TaskId;

        public Caller Capture(Arguments arguments)
        {
            StartTicks = DateTime.Now.Ticks;
            ExecutionTime = 0;
            Args = arguments;

            TaskId = Base56.GenerateUID(8, true);
            if (ServiceStopping)
            {
                string errMessage = "(555) Service is stopping, try again later.";
                IECaptErrorEventArgs seea = new IECaptErrorEventArgs(
                    TaskId,
                    Args,
                    ExecutionTime,
                    555,
                    errMessage);
                OnIECaptError(this, seea);
                Logger.ERROR(errMessage, TaskId, Args.CallerIdentity);
                return null;
            }
            Caller caller = RegisterTask();
            ReportStatus("Request started, task id is " + TaskId + ".");

            Thread t = new Thread(ReallyCapture);
            t.SetApartmentState(ApartmentState.STA);
            t.Start(TaskId);
            //t.Join();
            return caller;
        }

        private void ReallyCapture(object taskId)
        {
            IECapt iec = new IECapt();
            iec.OnComplete += new IECapt.CompleteEventHandler(iec_OnComplete);
            iec.OnError += new IECapt.ErrorEventHandler(iec_OnError);
            iec.OnStatus += new IECapt.StatusEventHandler(iec_OnStatus);
            iec.OnTarce += new IECapt.TarceEventHandler(iec_OnTarce);
            ReportStatus("Please wait, you are asking a URL " + Args.Url + "." );
            iec.Execute(
                Args.Url, 
                Args.OutputPath, 
                Args.ScreenWidth, 
                Args.MaxWait, 
                Args.Delay);
        }

        private Caller RegisterTask()
        {
            Caller caller = new Caller(Args.CallerIdentity, TaskId);
            try
            {
                lock (CurrentCallers)
                {
                    CurrentCallers.Add(TaskId, caller);
                }
            }
            catch
            {
            }
            return caller;
        }

        private void UnregisterTask()
        {
            try
            {
                lock (CurrentCallers)
                {
                    CurrentCallers.Remove(TaskId);
                }
            }
            catch
            {
            }
        }
        
        private void ReportStatus(string status)
        {
            IECaptStatusEventArgs isea = new IECaptStatusEventArgs(
                    TaskId,
                    Args,
                    status);
            OnIECaptStatus(this, isea);
            Logger.TRACE(status, TaskId, Args.CallerIdentity);
        }

        private void iec_OnTarce(object sender, StatusEventArgs e)
        {
            Logger.TRACE(e.Status, TaskId, Args.CallerIdentity);
        }

        private void iec_OnStatus(object sender, StatusEventArgs e)
        {
            ReportStatus(e.Status);
        }

        private void iec_OnError(object sender, ErrorEventArgs e)
        {
            int seven = e.StatusCode;
            string errMessage = seven.ToString();
            if (seven == 777)
            {
                errMessage = "(777) Invalid input.";
            }
            try
            {
                ExecutionTime = (DateTime.Now.Ticks - StartTicks) / 10000;
                IECaptErrorEventArgs seea = new IECaptErrorEventArgs(
                    TaskId,
                    Args,
                    ExecutionTime,
                    e.StatusCode,
                    errMessage);
                OnIECaptError(this, seea);
                Logger.ERROR(errMessage, TaskId, Args.CallerIdentity);
            }
            finally
            {
                UnregisterTask();
            }
        }

        private void iec_OnComplete(object sender, CompleteEventArgs e)
        {
            try
            {
                ReportStatus("Page capture complete.");
                bool hasErr = false;
                long snapSize = new FileInfo(Args.OutputPath).Length;
                long thumbnailSize = 0;
                if (Args.GetThumbnail && Args.ThumbnailOutputPath != null && Args.ThumbnailOutputPath.Trim().Length > 0)
                {
                    Thumbnail tn = new Thumbnail();
                    try
                    {
                        ReportStatus("We appear need to generate thumbnail.");
                        tn.Generate(
                            Args.OutputPath,
                            Args.ThumbnailOutputPath,
                            Args.ThumbnailWidth,
                            Args.ThumbnailHeight);
                        ReportStatus("Thumbnail done.");
                    }
                    catch (Exception ex)
                    {
                        hasErr = true;
                        ExecutionTime = (DateTime.Now.Ticks - StartTicks) / 10000;
                        IECaptErrorEventArgs seea = new IECaptErrorEventArgs(
                            TaskId,
                            Args,
                            ExecutionTime,
                            666,
                            "Error when generating thumbnail, the message is: " + ex.Message);
                        OnIECaptError(this, seea);
                        Logger.ERROR("(666) " + ex.Message, TaskId, Args.CallerIdentity);
                    }
                    thumbnailSize = new FileInfo(Args.ThumbnailOutputPath).Length;
                }
                if (Args.GetBodyText && Args.BodyTextOutputPath != null && Args.BodyTextOutputPath.Trim().Length > 0)
                {
                    try
                    {
                        ReportStatus("We appear need to parse content.");
                        //TODO
                        ReportStatus("Get content done.");
                    }
                    catch (Exception ex)
                    {
                        hasErr = true;
                        ExecutionTime = (DateTime.Now.Ticks - StartTicks) / 10000;
                        IECaptErrorEventArgs seea = new IECaptErrorEventArgs(
                            TaskId,
                            Args,
                            ExecutionTime,
                            888,
                            "Error when parsing content, the message is: " + ex.Message);
                        OnIECaptError(this, seea);
                        Logger.ERROR("(888) " + ex.Message, TaskId, Args.CallerIdentity);
                    }
                }
                if (!hasErr)
                {
                    ExecutionTime = (DateTime.Now.Ticks - StartTicks) / 10000;
                    IECaptCompleteEventArgs scea = new IECaptCompleteEventArgs(
                        TaskId,
                        Args,
                        snapSize,
                        thumbnailSize,
                        ExecutionTime);
                    OnIECaptComplete(this, scea);
                    ReportStatus("Request finished.");
                }
            }
            finally
            {
                UnregisterTask();
            }
        }

    }
}
